#!/usr/bin/python
# Copyright (C) 2007 Marco Catunda
# 
# This program is free software; you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published by the 
# Free Software Foundation; version 2 of the License 
# (http://www.opensource.org/licenses/gpl-license.php)
#
# This program is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
# for more details.
#
# You should have received a copy of the GNU General Public License along 
# with this program; if not, write to the Free Software Foundation, Inc., 
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Marco Catunda <marco.catunda-NOT-SPAM-THANKS@gmail.com>
import pysvn
import re
import os.path
import pprint
import sys
import os

class SVNBranch:
	def __init__( self ):
		self.client = pysvn.Client()
		info = self.client.info('.')

		self.svnurl = info.url
		self.svnrepo = info.repos

		# m = /<modulo>/<base>/...
		m = info.url[len(info.repos):]
		r = re.search( "^/(.*?)/.*", m )
		if r:
			self.svnmodulo = r.group(1)
		else:
			print "Nao foi possivel indentifcar o nome do modulo"
			sys.exit(1)

		self.svntrunk = "%s/%s/trunk" % (self.svnrepo,self.svnmodulo)
		self.svnbranch = "%s/%s/branches" % (self.svnrepo,self.svnmodulo)

	def getBranchPath( self ):
		return self.svnbranch

	def getBranchNeedMerge( self, onlyBranchName = None ):
		patternComentarioMerge = re.compile( "MERGE:(.*):(.*):(.*)" )

		listTrunkMerge = {}
		listBranchRevision = {} # {branchName: [rev1,rev2,rev3,...], ...}

		# Get comments about version merge of the trunk
		print "Getting trunk information..."
		listLog = self.client.log( self.svntrunk )
		listLog.reverse() # cronologic sort
		for log in listLog:
			r = patternComentarioMerge.search( log['message'] )
			if r:
				branchName = r.group(1)
				revStart = r.group(2)
				revEnd = r.group(3)
				if not listTrunkMerge.has_key(branchName):
					listTrunkMerge[branchName] = []
				listTrunkMerge[branchName].append( (revStart,revEnd) )

		# Get branch list. Get revision list for each branch
		if onlyBranchName:
			listBranch = [ {"name":"%s/%s" % (self.svnbranch,onlyBranchName)} ]
		else:
			print "Getting all branches information..."
			listBranch = self.client.ls( self.svnbranch )

		for branch in listBranch:
			branchName = os.path.basename(branch['name'])
			listBranchRevision[branchName] = []
			print "Getting branch information of '%s'..." % (branchName,)
			listLog = self.client.log(branch['name'])
			for log in listLog:
				listBranchRevision[branchName].append(log['revision'].number)
			listBranchRevision[branchName].sort()

		# Test if which branch need merge
		for branchName in listBranchRevision.keys():
			if listTrunkMerge.has_key(branchName):
				for trunkMerge in listTrunkMerge[branchName]:
					revStart = int(trunkMerge[0])
					revEnd   = int(trunkMerge[1])

					if not listBranchRevision[branchName]:
						print "Revision branch invalid of '%s' (there is no revision branch for trunk merge comment)" % branchName
						sys.exit(1)

					if listBranchRevision[branchName][0] != revStart:
						print "Revision branch invalid of '%s' (the revision merge comment of trunk differ branch revision)" % branchName
						sys.exit(1)

					else:
						# Delete all revisions before revEnd
						find = False
						while listBranchRevision[branchName] and listBranchRevision[branchName][0] <= revEnd:
							del listBranchRevision[branchName][0]

						# Is there is revisions, add it in first position, it will be used
						# in merge (revEnd+1)
						if listBranchRevision[branchName]:
							listBranchRevision[branchName].insert(0,revEnd+1)

		listBranchNeedMerge = {}
		for branchName in listBranchRevision.keys():
			if listBranchRevision[branchName]:
				listBranchNeedMerge[branchName] = (listBranchRevision[branchName][0],listBranchRevision[branchName][-1])

		return listBranchNeedMerge

	def branchMerge( self, branchName ):
		if self.isTrunk():
			listBranchNeedMerge = self.getBranchNeedMerge(branchName)
			if listBranchNeedMerge.has_key(branchName):
				cmd = "svn merge -r %d:%d %s/%s" % (listBranchNeedMerge[branchName][0], listBranchNeedMerge[branchName][1], branch.getBranchPath(), branchName)
				print cmd
				os.system(cmd)
			else:
				print "The branch '%s' not exist or doesn't need merge" % branchName
		else:
			print "The working copy is not on trunk, you have to use following command to change it"
			print "svn sw %s" % self.svntrunk

	def commitMerge( self, branchName ):
		if self.isTrunk():
			listBranchNeedMerge = self.getBranchNeedMerge(branchName) 
			if listBranchNeedMerge.has_key(branchName): 
				cmd = "svn commit -m 'MERGE:%s:%d:%d'" % (branchName, listBranchNeedMerge[branchName][0], listBranchNeedMerge[branchName][1])
				print cmd
				os.system(cmd) 
			else: 
				print "The branch '%s' not or doesn't need merge/commit" % branchName
		else:
			print "The working copy is not on trunk, you have to use following command to change it"
			print "svn sw %s" % self.svntrunk

	def isTrunk( self ):
		ok = False
		if os.path.basename(self.svnurl) == "trunk":
			ok = True
		return ok

if __name__ == "__main__":
	if len(sys.argv) > 1:
		if sys.argv[1] == "merge":
			op = "merge"
		if sys.argv[1] == "commit":
			op = "commit"
		if sys.argv[1] == "list":
			op = "list"
	else:
		print "Syntaxe: %s <merge|commit|list>" % sys.argv[0]
		sys.exit(1)

	if op == "list":
		branch = SVNBranch()
		listBranchNeedMerge = branch.getBranchNeedMerge()
		for branchName in listBranchNeedMerge.keys():
			print "%s: %d:%d" % (branchName, listBranchNeedMerge[branchName][0], listBranchNeedMerge[branchName][1])
		if not listBranchNeedMerge:
			print "No branchs need merge"

	if op == "merge":
		if len(sys.argv) > 2:
			branchName = sys.argv[2]
		else:
			print "Sintaxe: %s merge <branch-name>" % sys.argv[0]
			sys.exit(1)
		branch = SVNBranch()
		branch.branchMerge(branchName)

	if op == "commit":
		if len(sys.argv) > 2:
			branchName = sys.argv[2]
		else:
			print "Sintaxe: %s commit <branch-name>" % sys.argv[0]
			sys.exit(1)

		branch = SVNBranch()
		branch.commitMerge(branchName)
